
/*
    Revolution Engine
    Copyright (C) 2009 Felipe Apablaza

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/


/**
 *
 *  File: Matrix3.hpp
 *  Desc: Three-Order matrix class template (OpenGL-Compliant)
 *
 */

#ifndef __REVENG_MATH_MATRIX3_HPP__
#define __REVENG_MATH_MATRIX3_HPP__

#include "Base.hpp"
#include <cstring>

namespace RevEng
{
    namespace Math
    {
		template<typename T>
		struct Matrix3
		{
            T M11, M21, M31;
            T M12, M22, M32;
            T M13, M23, M33;
			
			Matrix3<T>();
			Matrix3<T>(const T* data);
			Matrix3<T>( T m11, T m12, T m13,
                        T m21, T m22, T m23,
                        T m31, T m32, T m33);
                        
			Matrix3<T>(const Matrix3<T> &m);
			
			Matrix3<T>& Inverse(T Det);
			Matrix3<T>& Inverse();
			Matrix3<T>& Transpose();
			
			T GetDeterminant() const;

			Matrix3<T> &operator= (const Matrix3<T> &M);

			bool operator == (const Matrix3<T> &M) const;
			bool operator != (const Matrix3<T> &M) const;

			Matrix3<T> operator+ (const Matrix3<T> &M)const;
			Matrix3<T> operator- (const Matrix3<T> &M)const;
			Matrix3<T> operator- () const;
			Matrix3<T> operator* (const Matrix3<T> &M)const;
			Matrix3<T> operator* (const T &S)const;
			Matrix3<T> operator/ (const T &S)const;
			
			Matrix3<T>& operator+= (const Matrix3<T> &M);
			Matrix3<T>& operator-= (const Matrix3<T> &M);
			Matrix3<T>& operator*= (const Matrix3<T> &M);
			Matrix3<T>& operator*= (const T &S);
			Matrix3<T>& operator/= (const T &S);
			
			friend Matrix3<T> operator* (T S, const Matrix3<T> &M)
			{
			    return M*S;
			}
			
			operator T* ();
			operator T* () const;
			operator const T* ();
			operator const T* () const;
		};
		
		template<typename T>
        Matrix3<T>::Matrix3() : M11(static_cast<T>(0)), M21(static_cast<T>(0)), M31(static_cast<T>(0)),
                                M12(static_cast<T>(0)), M22(static_cast<T>(0)), M32(static_cast<T>(0)),
                                M13(static_cast<T>(0)), M23(static_cast<T>(0)), M33(static_cast<T>(0))
        {
        }
        
        
        template<typename T>
		Matrix3<T>::Matrix3(const T* data)
		{
		    ::memcpy (*this, data, sizeof(T)*9);
		}
		
		
        template<typename T> 
		Matrix3<T>::Matrix3 (   T m11, T m12, T m13,
                                T m21, T m22, T m23,
                                T m31, T m32, T m33)
        :
            M11(m11), M21(m21), M31(m31),
            M12(m12), M22(m22), M32(m32),
            M13(m13), M23(m23), M33(m33)
		{
		}


		template<typename T> 
		Matrix3<T>::Matrix3(const Matrix3<T> &m)
		{
			::memcpy(*this, m, sizeof(T)*9);
		}
		

		template<typename T> 
		Matrix3<T>& Matrix3<T>::Inverse()
		{            
		    Matrix2<T> a11( M22, M23, 
                            M32, M33);
                            
		    Matrix2<T> a12( M21, M23, 
                            M31, M33);
                            
            Matrix2<T> a13( M21, M22, 
                            M31, M32);
		    
		    Matrix2<T> a21( M12, M13, 
                            M32, M33);
                            
            Matrix2<T> a22( M11, M13, 
                            M31, M33);
                            
            Matrix2<T> a23( M11, M12, 
                            M31, M32);
            
            Matrix2<T> a31( M12, M13, 
                            M22, M23);
		    
            Matrix2<T> a32( M11, M13, 
                            M21, M23);
                            
            Matrix2<T> a33( M11, M12, 
                            M21, M22);
            
            M11 = M11 * a11.GetDeterminant();
            M21 = - M21 * a21.GetDeterminant();
            M31 = M31 * a31.GetDeterminant();
            
            M12 = - M12 * a12.GetDeterminant();
            M22 = M22 * a22.GetDeterminant();
            M32 = - M32 * a32.GetDeterminant();
            
            M13 = M13 * a13.GetDeterminant();
            M23 = - M23 * a23.GetDeterminant();
            M33 = M33 * a33.GetDeterminant();

            Transpose();
            
            *this /= GetDeterminant();

            return  *this;
		}


		template<typename T> 
		Matrix3<T>& Matrix3<T>::Inverse(T Det)
		{
		    Matrix2<T> a11( M22, M23, M32, M33);
		    Matrix2<T> a12( M21, M23, M31, M33);
            Matrix2<T> a13( M21, M22, M31, M32);
		    Matrix2<T> a21( M12, M13, M32, M33);
            Matrix2<T> a22( M11, M13, M31, M33);
            Matrix2<T> a23( M11, M12, M31, M32);
            Matrix2<T> a31( M12, M13, M22, M23);
            Matrix2<T> a32( M11, M13, M21, M23);
            Matrix2<T> a33( M11, M12, M21, M22);
            
            M11 = M11 * a11.GetDeterminant();
            M21 = - M21 * a21.GetDeterminant();
            M31 = M31 * a31.GetDeterminant();
            
            M12 = - M12 * a12.GetDeterminant();
            M22 = M22 * a22.GetDeterminant();
            M32 = - M32 * a32.GetDeterminant();
            
            M13 = M13 * a13.GetDeterminant();
            M23 = - M23 * a23.GetDeterminant();
            M33 = M33 * a33.GetDeterminant();

            Transpose();
            
            *this /= Det;

            return  *this;
		}


		template<typename T> 
		Matrix3<T>& Matrix3<T>::Transpose()
		{
		    std::swap(M12, M21);
		    std::swap(M13, M31);
		    std::swap(M23, M32);
		    
			return *this;
		}


		template<typename T> 
		T Matrix3<T>::GetDeterminant() const
		{
		    Matrix2<T> a11( M22, M23, M32, M33);
		    Matrix2<T> a12( M21, M23, M31, M33);
            Matrix2<T> a13( M21, M22, M31, M32);
		    
			return  M11 * a11.GetDeterminant() - 
                    M21 * a12.GetDeterminant() + 
                    M31 * a13.GetDeterminant();
		}


		template<typename T> 
		Matrix3<T> &Matrix3<T>::operator= (const Matrix3<T> &M)
		{
			::memcpy(*this, M, sizeof(T)*9);
			return *this;
		}


        template<typename T> 
        bool Matrix3<T>::operator == (const Matrix3<T> &M) const
        {
            if (Equals<T>(M11, M.M11) == false)
                return false;
                
            if (Equals<T>(M21, M.M21) == false)
                return false;
                
            if (Equals<T>(M31, M.M31) == false)
                return false;
                
            if (Equals<T>(M12, M.M12) == false)
                return false;
                
            if (Equals<T>(M22, M.M22) == false)
                return false;
                
            if (Equals<T>(M32, M.M32) == false)
                return false;
                
            if (Equals<T>(M13, M.M13) == false)
                return false;
                
            if (Equals<T>(M23, M.M23) == false)
                return false;
                
            if (Equals<T>(M33, M.M33) == false)
                return false;
            
            return true;
        }
        
        
        template<typename T> 
		bool Matrix3<T>::operator != (const Matrix3<T> &M) const
		{
		    return ! (*this == M);
		}


		template<typename T> 
		Matrix3<T> Matrix3<T>::operator+ (const Matrix3<T> &M)const
		{
			return Matrix3<T>
			(
				M11+M.M11, M12+M.M12, M13+M.M13,
				M21+M.M21, M22+M.M22, M23+M.M23,
				M31+M.M31, M32+M.M32, M33+M.M33
			);
		}


		template<typename T> 
		Matrix3<T> Matrix3<T>::operator- (const Matrix3<T> &M)const
		{
			return Matrix3<T>
			(
				M11-M.M11, M12-M.M12, M13-M.M13,
				M21-M.M21, M22-M.M22, M23-M.M23,
				M31-M.M31, M32-M.M32, M33-M.M33
			);
		}


		template<typename T> 
		Matrix3<T> Matrix3<T>::operator- () const
		{
			return Matrix3<T>
			(
				-M11, -M12, -M13,
				-M21, -M22, -M23,
				-M31, -M32, -M33
			);
		}


		template<typename T> 
		Matrix3<T> Matrix3<T>::operator* (const Matrix3<T> &M) const
		{
			return Matrix3<T>
			(
				M11*M.M11 + M12*M.M21 + M13*M.M31,
				M11*M.M12 + M12*M.M22 + M13*M.M32,
				M11*M.M13 + M12*M.M23 + M13*M.M33,

				M21*M.M11 + M22*M.M21 + M23*M.M31,
				M21*M.M12 + M22*M.M22 + M23*M.M32,
				M21*M.M13 + M22*M.M23 + M23*M.M33,

				M31*M.M11 + M32*M.M21 + M33*M.M31,
				M31*M.M12 + M32*M.M22 + M33*M.M32,
				M31*M.M13 + M32*M.M23 + M33*M.M33
			);
		}


		template<typename T> 
		Matrix3<T> Matrix3<T>::operator* (const T &S)const
		{
			return Matrix3<T>
			(
				M11*S, M12*S, M13*S,
				M21*S, M22*S, M23*S,
				M31*S, M32*S, M33*S
			);
		}


		template<typename T> 
		Matrix3<T> Matrix3<T>::operator/ (const T &S)const
		{
		    T InvS = static_cast<T>(1)/S;
		    
		    
			return Matrix3<T>
			(
				M11*InvS, M12*InvS, M13*InvS,
				M21*InvS, M22*InvS, M23*InvS,
				M31*InvS, M32*InvS, M33*InvS
			);
		}

		template<typename T> 
		Matrix3<T>& Matrix3<T>::operator+= (const Matrix3<T> &M)
		{
		    M11 += M.M11;
		    M21 += M.M21;
		    M31 += M.M31;
		    
		    M12 += M.M12;
		    M22 += M.M22;
		    M32 += M.M32;
		    
		    M13 += M.M13;
		    M23 += M.M23;
		    M33 += M.M33;
		    
			return *this;
		}


		template<typename T> 
		Matrix3<T>& Matrix3<T>::operator-= (const Matrix3<T> &M)
		{
            M11 -= M.M11;
		    M21 -= M.M21;
		    M31 -= M.M31;
		    
		    M12 -= M.M12;
		    M22 -= M.M22;
		    M32 -= M.M32;
		    
		    M13 -= M.M13;
		    M23 -= M.M23;
		    M33 -= M.M33;
		    
			return *this;
		}


		template<typename T> 
		Matrix3<T>& Matrix3<T>::operator*= (const Matrix3<T> &M)
		{
			Matrix3<T> Result;

            Result.M11 = M11*M.M11 + M12*M.M21 + M13*M.M31;
            Result.M12 = M11*M.M12 + M12*M.M22 + M13*M.M32;
            Result.M13 = M11*M.M13 + M12*M.M23 + M13*M.M33;

            Result.M21 = M21*M.M11 + M22*M.M21 + M23*M.M31;
            Result.M22 = M21*M.M12 + M22*M.M22 + M23*M.M32;
            Result.M23 = M21*M.M13 + M22*M.M23 + M23*M.M33;

            Result.M31 = M31*M.M11 + M32*M.M21 + M33*M.M31;
            Result.M32 = M31*M.M12 + M32*M.M22 + M33*M.M32;
            Result.M33 = M31*M.M13 + M32*M.M23 + M33*M.M33;

			return *this = Result;
		}


		template<typename T> 
		Matrix3<T>& Matrix3<T>::operator*= (const T &S)
		{
			M11 *= S;
		    M21 *= S;
		    M31 *= S;
		    
		    M12 *= S;
		    M22 *= S;
		    M32 *= S;
		    
		    M13 *= S;
		    M23 *= S;
		    M33 *= S;
		    
			return *this;
		}


		template<typename T> 
		Matrix3<T>& Matrix3<T>::operator/= (const T &S)
		{
			M11 /= S;
		    M21 /= S;
		    M31 /= S;
		    
		    M12 /= S;
		    M22 /= S;
		    M32 /= S;
		    
		    M13 /= S;
		    M23 /= S;
		    M33 /= S;
		    
			return *this;
		}


		template<typename T> 
		Matrix3<T> operator* (T S, const Matrix3<T> &M)
		{
			return M*S;
		}


		template<typename T> 
		Matrix3<T>::operator T* ()
		{
			return &M11;
		}		
		
		
		template<typename T> 
		Matrix3<T>::operator T* () const
		{
			return &M11;
		}		
		
		
		template<typename T> 
		Matrix3<T>::operator const T* ()
		{
			return &M11;
		}		
		
		
		template<typename T> 
		Matrix3<T>::operator const T* () const
		{
			return &M11;
		}		
    }
}
#endif // __REVENG_MATH_MATRIX4_HPP__
